﻿using System;
using System.Buffers;
using System.Net.Sockets.Kcp;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;

namespace Cemit.KcpSocket
{
    [System.Obsolete("以组合方式使用KCP")]
    public class KcpSocket
    {
        public Socket Client { get; }

        private KcpHandle kcpHandle;
        private Kcp kcp;

        private byte[] receiveBuffer;

        public KcpSocket(uint appId)
        {
            Client = GetUdpSocket();

            kcpHandle = new KcpHandle();
            kcpHandle.SendFunc += UdpSend;

            kcp = new Kcp(appId, kcpHandle);

            kcp.NoDelay(1, 10, 2, 1);//fast
            kcp.WndSize(64, 64);
            kcp.SetMtu(512);
        }

        public KcpSocket Bind(IPEndPoint localIP)
        {
            Client.Bind(localIP);
            return this;
        }

        public KcpSocket Connect(IPEndPoint remoteIP)
        {
            Client.Connect(remoteIP);
            return this;
        }

        private static Socket GetUdpSocket()
        {
            return new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        }

        /// <summary>启动，在启动之前需要进行Connect或者Bind</summary>
        public KcpSocket Start()
        {
            if (Client == null)
            {
                throw new Exception("KcpSocket启动前需要先进行Connect或Bind！");
            }

            //启动KCP的Update，每5ms执行一次
            Task.Run(async () => 
            {
                kcp.Update(DateTime.UtcNow);
                await Task.Delay(5);
            });

            //udpClient.
            //UdpClient.Select();

            //Task.Run(async () => 
            //{
            //    UdpReceiveResult ach = await Client.ReceiveAsync();
            //    Client.BeginReceive();
            //});

            return this;
        }

        /// <summary>返回队列中的下一条数据，没有数据则返回-1，连接请求断开则返回0</summary>
        public int Receive(Span<byte> buffer)
        {
            int length = kcp.PeekSize();

            if (length == 0)
            {
                return -1;
            }

            return kcp.Recv(buffer);
        }

        /// <summary>发送数据</summary>
        /// <returns>返回值不为0则表示发送失败</returns>
        public int Send(Span<byte> buffer)
        {
            return kcp.Send(buffer);
        }

        /// <summary>使用Udp将Kcp数据发出</summary>
        private void UdpSend(Memory<byte> memory)
        {
            //await Client.SendAsync(memory.ToArray(), memory.Length);
        }

        class KcpHandle : IKcpCallback
        {
            public Action<Memory<byte>> SendFunc;

            public void Output(IMemoryOwner<byte> buffer, int avalidLength)
            {
                using (buffer)
                {
                    SendFunc?.Invoke(buffer.Memory.Slice(0, avalidLength));
                }
            }

            public IMemoryOwner<byte> RentBuffer(int length)
            {
                //返回null则自动分配缓存
                return null;
            }
        }
    }
}
